package com.xinxin.base.service;

import org.springframework.data.redis.core.ZSetOperations;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @author ys
 * @date 2021/5/20
 */
public interface IRedisService {

    void setString(String key, String value);

    void setString(String key, String value, long timeout, TimeUnit unit);

    void setObject(String key, Object value);

    void setObject(String key, Object value, long timeout, TimeUnit unit);

    String getString(String key);

    <T> T getObject(String key, Class<T> clazz);

    /**
     * 从缓存获取，存在则直接返回
     * 否则从Supplier获取，并且不为空时缓存5分钟
     */
    default <T> T orElseGet(String key, Class<T> clazz, Supplier<T> supplier) {
        Optional<T> object = Optional.ofNullable(getObject(key, clazz));
        if (object.isPresent()) {
            return object.get();
        }

        object = Optional.ofNullable(supplier.get());
        object.ifPresent(t -> setObject(key, t, 5, TimeUnit.MINUTES));
        return object.orElse(null);
    }

    Long getExpire(String key);

    Boolean delete(String key);

    Boolean setnx(String key, Object value, long timeout, TimeUnit unit);

    double arithmetic2RedisScore(int score, LocalDateTime endTime);

    /**
     * 通过 {@link #arithmeticScore(String, Object)} 调用此方法时
     * 如果 {@link #score(String, Object)} 返回 -1，说明 Redis 里不存在
     * 此方法输入 -1 会返回 0
     */
    int redis2ArithmeticScore(Double score);

    void arithmeticAdd(String key, Object value, int score, LocalDateTime endTime);

    /**
     * 如果 {@link #score(String, Object)} 返回 -1，说明 Redis 里不存在
     * 则此方法会返回 0
     */
    int arithmeticScore(String key, Object value);

    void add(String key, Object value, double score);

    /**
     * 如果返回 -1，说明 Redis 里不存在
     */
    Double score(String key, Object value);

    /**
     * 如果返回 -1，说明 Redis 里不存在
     */
    Long rank(String key, Object value);

    Set<ZSetOperations.TypedTuple<Object>> rangeWithScores(String key, long start, long end);

    Set<Object> range(String key, long start, long end);
}
